/**
 *    Copyright (C) 2008,2009  Victor Smirnov <aist11@gmail.com>
 *
 *    This program is free software; you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation; either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License along
 *    with this program; if not, write to the Free Software Foundation, Inc.,
 *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 *    See LICENSE.exceptions in the root folder of this project for possible
 *    exceptions
 *
 */

#ifndef _CUBEFS_CORE_BTREE_PAGES_NODE_FACTORY_HPP
#define	_CUBEFS_CORE_BTREE_PAGES_NODE_FACTORY_HPP


#include <cubefs/core/tools/packed_map.hpp>
#include <cubefs/core/tools/reflection.hpp>
#include <cubefs/core/container/container.hpp>
#include <cubefs/core/btree/pages/node_base.hpp>

namespace cubefs    {
namespace btree     {

using namespace cubefs::tools;
using namespace cubefs::ctr;

#pragma pack(1)

template <
        typename Profile,
        typename Key,
        typename Value,
        typename ComponentList,
        typename BaseType,
        int      Indexes,
        bool     PackedMapType,
        typename DescriptorType
>
class NodePage: public PageBuilder<Profile, ComponentList, BaseType>
{

public:

    typedef NodePage<
                Profile,
                Key,
                Value,
                ComponentList,
                BaseType,
                Indexes,
                PackedMapType,
                DescriptorType
    >                                                                           Me;

    typedef PageBuilder<Profile, ComponentList, BaseType>                       Base;

    typedef typename BaseType::PageMgr                                          PageMgr;

private:
    struct MapConstants: public GlobalConstants
    {
        static const int BLOCK_SIZE = PageMgr::PAGE_SIZE - sizeof(Base);
    };

public:
    
    typedef typename PackedMapFactory<
            Key,
            Value,
            MapConstants,
            Indexes,
            Key,
            PackedMapType
    >::Type                                                                     Map;
    
    typedef DescriptorType                                                      Descriptor;

private:

    Map map_;

    static PageMetadata *reflection_;

public:

    static const long INDEXES                                                   = Indexes;

    typedef Key                                                                 KeyType;
    typedef Value                                                               ValueType;

    NodePage(): Base(), map_() {
    	CubefsMarkerProc();
    }

    static Int hash() {
        return reflection_->Hash();
    }

    static bool is_abi_compatible() {
        return reflection_->IsAbiCompatible();
    }

    static PageMetadata *reflection() {
        return reflection_;
    }

    const Map &map() const
    {
        return map_;
    }

    Map &map()
    {
        return map_;
    }

    void Reindex()
    {
        map().Reindex();
    }

    Int data_size() const
    {
        Int size = map().size();
        Me* me = NULL;
        return (Int)(BigInt)&me->map().key(size);
    }

    void BuildFieldsList(MetadataList &list, Long &abi_ptr) const {
        Base::BuildFieldsList(list, abi_ptr);
        FieldFactory<Map>::create(list, map(), "MAP", abi_ptr);
    }

    template <typename PageType>
    void CopyFrom(PageType* page)
    {
        Base::CopyFrom(page);

        map().size()   = page->map().size();

        for (Int c = 0; c < page->map().size(); c++)
        {
            for (Int d = 0; d < INDEXES; d++)
            {
                map().key(d, c) = page->map().key(d, c);
            }
            map().data(c) = page->map().data(c);
        }

        for (Int c = map().size(); c < map().max_size(); c++)
        {
            for (Int d = 0; d < INDEXES; d++)
            {
                map().key(d, c) = 0;
            }
            map().data(c) = 0;
        }
    }

    static Int get_page_size(const void* buf) {
        const Me* me = static_cast<const Me*>(buf);
        return me->data_size();
    }

    static Int Init() {
        if (reflection_ == NULL)
        {
            Map::Init();

            Long abi_ptr = 0;
            Me* me = 0;
            MetadataList list;
            me->BuildFieldsList(list, abi_ptr);

            Int hash0 = 1234567 + Descriptor::Root + 2 * Descriptor::Leaf + 4 * Descriptor::Level;

            Int attrs = BTREE + Descriptor::Root * ROOT + Descriptor::Leaf * LEAF;

            reflection_ = new PageMetadataImpl("BTREE_PAGE", list, attrs, hash0, &get_page_size, PageMgr::PAGE_SIZE);
        }
        else {}

        return reflection_->Hash();
    }

    void *operator new(size_t size, PageMgr &mgr) {
    	typename PageMgr::Page *adr = mgr.create_new();
    	cout<<"NodeFactory: "<<adr<<" "<<adr->id().value()<<endl;
        return adr;
    }

    void operator delete(void *buf, size_t size) {}
};


template <
        typename Profile,
        typename Key,
        typename Value,
        typename ComponentList,
        typename BaseType,
        int      Indexes,
        bool     PackedMapType,
        typename DescriptorType
>
PageMetadata* NodePage<Profile, Key, Value, ComponentList, BaseType, Indexes, PackedMapType, DescriptorType>::reflection_ = NULL;



template <
            typename Profile,
            typename Name,
            typename Key,
            typename Value,
            Int      Indexes,
            bool     PackedMapType,
            typename List,
            typename BasePartsList,
            typename Descriptor
> class NodePageFactory {
    typedef typename TypeLocator<
                Profile,
                NodeBaseFactory<
                    Name,
                    BasePartsList
                >
    >::Type                                                                     NodeBaseType;

public:
    typedef NodePage<
            Profile,
            Key,
            Value,
            List,
            NodeBaseType,
            Indexes,
            PackedMapType,
            Descriptor
    >                                                                           Type;
};



#pragma pack()

}
}

#endif // _CUBEFS_CORE_BTREE_PAGES_NODE_FACTORY_HPP
